{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N7ITxKLUkX0v"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "yOYx6tzSnWQ3"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6xgB0Oz5eGSQ"
      },
      "source": [
        "# グラフと関数の基礎"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w4zzZVZtQb1w"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/intro_to_graphs\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\"> TensorFlow.orgで表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示{</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード/a0}</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBKqnXI9GOax"
      },
      "source": [
        "# グラフと `tf.function` の基礎\n",
        "\n",
        "このガイドは、TensorFlow の仕組みを説明するために、TensorFlow と Keras 基礎を説明します。今すぐ Keras に取り組みたい方は、[Keras のガイド一覧](keras/)を参照してください。\n",
        "\n",
        "このガイドでは、グラフ取得のための単純なコード変更、格納と表現、およびモデルの高速化とエクスポートを行うための使用方法について、TensorFlow の中核的な仕組みを説明します。\n",
        "\n",
        "注意: TensorFlow 1.x のみの知識をお持ちの場合は、このガイドでは、非常に異なるグラフビューが紹介されています。\n",
        "\n",
        "これは、基礎を概説したガイドです。これらの概念の徹底ガイドについては、[`tf.function` ガイド](function)を参照してください。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v0DdlfacAdTZ"
      },
      "source": [
        "## グラフとは？\n",
        "\n",
        "前回の 3 つのガイドでは、TensorFlow の **Eager** execution について説明しました。これは、TensorFlow 演算が演算ごとにPythonによって実行され、結果を Python に返すことを意味します。Eager TensorFlow は GPU を活用し、変数、テンソル、さらには演算を GPU と TPU に配置することができます。また、デバックも簡単に行えます。\n",
        "\n",
        "一部のユーザーは、Python から移動する必要はありません。\n",
        "\n",
        "ただし、TensorFlow を Python で演算ごとに実行すると、ほかの方法では得られない多数の高速化機能が利用できなくなります。Python からテンソルの計算を抽出できる場合は、*グラフ* にすることができます。\n",
        "\n",
        "**グラフとは、計算のユニットを表す一連の `tf.Operation` オブジェクトと、演算間を流れるデータのユニットを表す `tf.Tensor` オブジェクトを含むデータ構造です。** `tf.Graph` コンテキストで定義されます。これらのグラフはデータ構造であるため、元の Python コードがなくても、保存、実行、および復元することができます。\n",
        "\n",
        "次は、TensorBoard で視覚化された単純な二層グラフです。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvQ5aBuRGT1o"
      },
      "source": [
        "![a two-layer tensorflow graph](https://storage.cloud.google.com/tensorflow.org/images/two-layer-network.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DHpY3avXGITP"
      },
      "source": [
        "## グラフのメリット\n",
        "\n",
        "グラフを使用すると、柔軟性が大幅に向上し、モバイルアプリケーション。組み込みデバイス、バックエンドサーバーといった Python インタプリタのない環境でも TensorFlow グラフを使用できます。TensorFlow は、Python からエクスポートされた場合に、保存されるモデルの形式としてグラフを使用します。\n",
        "\n",
        "また、グラフは最適化を簡単に行えるため、コンパイラは次のような変換を行えます。\n",
        "\n",
        "- 計算に定数ノードを畳み込むで、テンソルの値を統計的に推論します*（「定数畳み込み」）*。\n",
        "- 独立した計算のサブパートを分離し、スレッドまたはデバイスに分割します。\n",
        "- 共通部分式を取り除き、算術演算を単純化します。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o1x1EOD9GjnB"
      },
      "source": [
        "これやほかの高速化を実行する [Grappler](./graph_optimization.ipynb) という総合的な最適化システムがあります。\n",
        "\n",
        "まとめると、グラフは非常に便利なもので、**複数のデバイス**で、TensorFlow の**高速化**、**並列化**、および効率化を期待することができます。\n",
        "\n",
        "ただし、便宜上、Python で機械学習モデル（またはその他の計算）を定義した後、必要となったときに自動的にグラフを作成することをお勧めします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pSZebVuWxDXu"
      },
      "source": [
        "# グラフのトレース\n",
        "\n",
        "TensorFlow でグラフを作成する方法は、直接呼出しまたはデコレータのいずれかとして `tf.function` を使用することです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "goZwOXp_xyQj"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import timeit\n",
        "from datetime import datetime"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HKbLeJ1y0Umi"
      },
      "outputs": [],
      "source": [
        "# Define a Python function\n",
        "def function_to_get_faster(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Create a `Function` object that contains a graph\n",
        "a_function_that_uses_a_graph = tf.function(function_to_get_faster)\n",
        "\n",
        "# Make some tensors\n",
        "x1 = tf.constant([[1.0, 2.0]])\n",
        "y1 = tf.constant([[2.0], [3.0]])\n",
        "b1 = tf.constant(4.0)\n",
        "\n",
        "# It just works!\n",
        "a_function_that_uses_a_graph(x1, y1, b1).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MT7U8ozok0gV"
      },
      "source": [
        "`tf.function` 化された関数は、[Python コーラブル]()で、Python 相当と同じように機能します。特定のクラス（`python.eager.def_function.Function`）を使用しますが、ユーザーにとっては、トレースできないものと同じように動作します。\n",
        "\n",
        "`tf.function` は、それが呼び出す Python 関数を再帰的にトレースします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rpz08iLplm9F"
      },
      "outputs": [],
      "source": [
        "def inner_function(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Use the decorator\n",
        "@tf.function\n",
        "def outer_function(x):\n",
        "  y = tf.constant([[2.0], [3.0]])\n",
        "  b = tf.constant(4.0)\n",
        "\n",
        "  return inner_function(x, y, b)\n",
        "\n",
        "# Note that the callable will create a graph that\n",
        "# includes inner_function() as well as outer_function()\n",
        "outer_function(tf.constant([[1.0, 2.0]])).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P88fOr88qgCj"
      },
      "source": [
        "TensorFlow 1.x を使用したことがある場合は、`Placeholder` または `tf.Sesssion` をまったく定義する必要がないことに気づくでしょう。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wfeKf0Nr1OEK"
      },
      "source": [
        "## フローの制御と副次的影響\n",
        "\n",
        "フロー制御とループは、デフォルトで `tf.autograph` によって TensorFlow に変換されます。Autograph は、ループコンストラクトの標準化、アンロール、および [AST](https://docs.python.org/3/library/ast.html) マニピュレーションなどのメソッドを組み合わせて使用します。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PFObpff1BMEb"
      },
      "outputs": [],
      "source": [
        "def my_function(x):\n",
        "  if tf.reduce_sum(x) <= 1:\n",
        "    return x * x\n",
        "  else:\n",
        "    return x-1\n",
        "\n",
        "a_function = tf.function(my_function)\n",
        "\n",
        "print(\"First branch, with graph:\", a_function(tf.constant(1.0)).numpy())\n",
        "print(\"Second branch, with graph:\", a_function(tf.constant([5.0, 5.0])).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hO4DBUNZBMwQ"
      },
      "source": [
        "Autograph 変換を直接呼び出して、Python が TensorFlow 演算に変換される様子を確認することができます。これはほとんど解読不能ですが、変換を確認することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8x6RAqza1UWf"
      },
      "outputs": [],
      "source": [
        "# Don't read the output too carefully.\n",
        "print(tf.autograph.to_code(my_function))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GZ4Ieg6tBE6l"
      },
      "source": [
        "Autograph は、`if-then` 句、ループ、 `break`、`return`、`continue` などを自動的に変換します。\n",
        "\n",
        "ほとんどの場合、Autograph の動作に特別な考慮はいりませんが、いくつかの注意事項があり、これについては [tf.function ガイド](./function.ipynb)のほか、[Autograph 完全リファレンス](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/g3doc/reference/index.md)が役立ちます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A6NHDp7vAKcJ"
      },
      "source": [
        "## 高速化の確認\n",
        "\n",
        "tensor-using 関数を `tf.function` でラッピングするだけでは、コードは高速化しません。単一のマシンで数回呼び出された小さな関数では、グラフまたはグラフの一部の呼び出しにかかるオーバーヘッドによってランタイムが占有されてしまうことがあります。また、GPU 大きな負荷をかける畳み込みのスタックなど、計算のほとんどがすでにアクセラレータで発生している場合は、グラフの高速化をあまり確認できません。\n",
        "\n",
        "複雑な計算については、グラフによって大幅な高速化を得ることができます。これは、グラフが Python からデバイスへの通信や一部の高速化の実装を減らすためです。\n",
        "\n",
        "次のコードは、小さな密のレイヤーでの数回の実行にかかる時間を計測します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zbNndv-0BeO4"
      },
      "outputs": [],
      "source": [
        "# Create an oveerride model to classify pictures\n",
        "class SequentialModel(tf.keras.Model):\n",
        "  def __init__(self, **kwargs):\n",
        "    super(SequentialModel, self).__init__(**kwargs)\n",
        "    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))\n",
        "    self.dense_1 = tf.keras.layers.Dense(128, activation=\"relu\")\n",
        "    self.dropout = tf.keras.layers.Dropout(0.2)\n",
        "    self.dense_2 = tf.keras.layers.Dense(10)\n",
        "\n",
        "  def call(self, x):\n",
        "    x = self.flatten(x)\n",
        "    x = self.dense_1(x)\n",
        "    x = self.dropout(x)\n",
        "    x = self.dense_2(x)\n",
        "    return x\n",
        "\n",
        "input_data = tf.random.uniform([60, 28, 28])\n",
        "\n",
        "eager_model = SequentialModel()\n",
        "graph_model = tf.function(eager_model)\n",
        "\n",
        "print(\"Eager time:\", timeit.timeit(lambda: eager_model(input_data), number=10000))\n",
        "print(\"Graph time:\", timeit.timeit(lambda: graph_model(input_data), number=10000))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kNGuLnjK1c5U"
      },
      "source": [
        "### 多層型関数\n",
        "\n",
        "関数をトレースする場合、**多層型**の `Function` オブジェクトを作成します。多層型関数は  Pythonコーラブルで、1つの API の背後にあるいくつかの具象関数グラフをカプセル化します。\n",
        "\n",
        "この `Function` は、あらゆる `dtypes` と形状に使用できます。新しい引数シグネチャでそれを呼び出すたびに、元の関数が新しい引数で再トレースされます。`Function` は、そのトレースに対応する `tf.Graph` を `concrete_function` に格納します。関数がすでにそのような引数でトレースされている場合は、トレース済みのグラフが取得されます。\n",
        "\n",
        "概念的に、次のようになります。\n",
        "\n",
        "- **`tf.Graph`** は計算を説明する未加工のポータブルなデータ構造である\n",
        "- **`Function`** は、ConcreteFunctions のキャッシュ、トレース、およびディスパッチャーである\n",
        "- **`ConcreteFunction`** は、Python からグラフを実行できるグラフの Eager 対応ラッパーである\n",
        "\n",
        "### 多層型関数の検査\n",
        "\n",
        "`a_function` を検査できます。これはPython 関数 `my_function` に対して `tf.function`  を呼び出した結果です。この例では、3 つの引数で `a_function` を呼び出すことで、3 つの具象関数を得られています。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7heuYuwn2edE"
      },
      "outputs": [],
      "source": [
        "print(a_function)\n",
        "\n",
        "print(\"Calling a `Function`:\")\n",
        "print(\"Int:\", a_function(tf.constant(2)))\n",
        "print(\"Float:\", a_function(tf.constant(2.0)))\n",
        "print(\"Rank-1 tensor of floats\", a_function(tf.constant([2.0, 2.0, 2.0])))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "s1c8db0cCW2k"
      },
      "outputs": [],
      "source": [
        "# Get the concrete function that works on floats\n",
        "print(\"Inspecting concrete functions\")\n",
        "print(\"Concrete function for float:\")\n",
        "print(a_function.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.float32)))\n",
        "print(\"Concrete function for tensor of floats:\")\n",
        "print(a_function.get_concrete_function(tf.constant([2.0, 2.0, 2.0])))\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JLTNuv_CCZXK"
      },
      "outputs": [],
      "source": [
        "# Concrete functions are callable\n",
        "# Note: You won't normally do this, but instead just call the containing `Function`\n",
        "cf = a_function.get_concrete_function(tf.constant(2))\n",
        "print(\"Directly calling a concrete function:\", cf(tf.constant(2)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PTHNiHLXH9es"
      },
      "source": [
        "この例では、スタックの非常に奥を調べています。具体的にトレースを管理していない限り、通常は、ここに示されるように具象関数を呼び出す必要はありません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V11zkxU22XeD"
      },
      "source": [
        "# Eager execution でのデバッグ\n",
        "\n",
        "スタックトレースが長い場合、特に `tf.Graph` または `with tf.Graph().as_default()` の参照が含まれる場合、グラフコンテキストで実行している可能性があります。TensorFlow のコア関数は Keras の `model.fit()` などのグラフコンテキストを使用します。\n",
        "\n",
        "Eager execution をデバッグする方がはるかに簡単であることがよくあります。スタックトレースは比較的に短く、理解しやすいからです。\n",
        "\n",
        "グラフのデバックが困難な場合は、Eager execution に戻ってデバックすることができます。\n",
        "\n",
        "Eager で実行していることを確認するには、次を行います。\n",
        "\n",
        "- メソッドとレイヤーを直接コーラブルとして呼び出す\n",
        "\n",
        "- Keras compile/fit を使用している場合、コンパイル時に **`model.compile(run_eagerly=True)`** を使用する\n",
        "\n",
        "- **`tf.config.experimental_run_functions_eagerly(True)`** でグローバル実行モードを設定する\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iTHvdQfRICJb"
      },
      "source": [
        "### `run_eagerly=True` を使用する"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kqzBV2rSzvpC"
      },
      "outputs": [],
      "source": [
        "# Define an identity layer with an eager side effect\n",
        "class EagerLayer(tf.keras.layers.Layer):\n",
        "  def __init__(self, **kwargs):\n",
        "    super(EagerLayer, self).__init__(**kwargs)\n",
        "    # Do some kind of initialization here\n",
        "\n",
        "  def call(self, inputs):\n",
        "    print(\"\\nCurrently running eagerly\", str(datetime.now()))\n",
        "    return inputs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5DFvc9ySr7t3"
      },
      "outputs": [],
      "source": [
        "# Create an override model to classify pictures, adding the custom layer\n",
        "class SequentialModel(tf.keras.Model):\n",
        "  def __init__(self):\n",
        "    super(SequentialModel, self).__init__()\n",
        "    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))\n",
        "    self.dense_1 = tf.keras.layers.Dense(128, activation=\"relu\")\n",
        "    self.dropout = tf.keras.layers.Dropout(0.2)\n",
        "    self.dense_2 = tf.keras.layers.Dense(10)\n",
        "    self.eager = EagerLayer()\n",
        "\n",
        "  def call(self, x):\n",
        "    x = self.flatten(x)\n",
        "    x = self.dense_1(x)\n",
        "    x = self.dropout(x)\n",
        "    x = self.dense_2(x)\n",
        "    return self.eager(x)\n",
        "\n",
        "# Create an instance of this model\n",
        "model = SequentialModel()\n",
        "\n",
        "# Generate some nonsense pictures and labels\n",
        "input_data = tf.random.uniform([60, 28, 28])\n",
        "labels = tf.random.uniform([60])\n",
        "\n",
        "loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U3-hcwmpI3Sv"
      },
      "source": [
        "まず、Eager を使用せずにモデルをコンパイルします。モデルはトレースされません。名前にも関わらず、`compile` は、損失関数、最適化、およびトレーニングパラメータのセットアップしか行いません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "w2GdwhB_KQlw"
      },
      "outputs": [],
      "source": [
        "model.compile(run_eagerly=False, loss=loss_fn)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WLMXk1uxKQ44"
      },
      "source": [
        "ここで、`fit` を呼び出し、関数がトレース（2 回）されると Eager 効果が実行しなくなるのを確認します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VCoLlZDythZ8"
      },
      "outputs": [],
      "source": [
        "model.fit(input_data, labels, epochs=3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jOk6feLOK1pR"
      },
      "source": [
        "ただし、エポックを 1 つでも Eager で実行すると、Eager の副次的作用が 2 回現れます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MGIYwrKpK06e"
      },
      "outputs": [],
      "source": [
        "print(\"Running eagerly\")\n",
        "# When compiling the model, set it to run eagerly\n",
        "model.compile(run_eagerly=True, loss=loss_fn)\n",
        "\n",
        "model.fit(input_data, labels, epochs=1)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qwq_cnc8Lwf8"
      },
      "source": [
        "### `experimental_run_functions_eagerly` を使用する\n",
        "\n",
        "また、すべてを Eager で実行するよにグローバルに設定することができます。これは、トレースし直した場合にのみ機能することに注意してください。トレースされた関数は、トレースされたままとなり、グラフとして実行します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oFSxRtcptYpe"
      },
      "outputs": [],
      "source": [
        "# Now, globally set everything to run eagerly\n",
        "tf.config.experimental_run_functions_eagerly(True)\n",
        "print(\"Run all functions eagerly.\")\n",
        "\n",
        "# First, trace the model, triggering the side effect\n",
        "polymorphic_function = tf.function(model)\n",
        "\n",
        "# It was traced...\n",
        "print(polymorphic_function.get_concrete_function(input_data))\n",
        "\n",
        "# But when you run the function again, the side effect happens (both times).\n",
        "result = polymorphic_function(input_data)\n",
        "result = polymorphic_function(input_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pD-AQxEhua4E"
      },
      "outputs": [],
      "source": [
        "# Don't forget to set it back when you are done\n",
        "tf.config.experimental_run_functions_eagerly(False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sm0bNFp8PX53"
      },
      "source": [
        "# トレースとパフォーマンス\n",
        "\n",
        "トレースにはある程度のオーバーヘッドがかかります。小さな関数のトレースは素早く行えますが、大規模なモデルであればかなりの時間がかかる場合があります。パフォーマンスが上昇するとこの部分の時間は迅速に取り戻されますが、大規模なモデルのトレーニングの最初の数エポックでは、トレースによって遅延が発生する可能性があることに注意しておくことが重要です。\n",
        "\n",
        "モデルの規模に関係なく、頻繁にトレースするのは避けたほうがよいでしょう。[tf.function ガイドのこのセクション](function.ipynb#when_to_retrace)では、入力仕様を設定し、テンソル引数を使用して再トレースを回避する方法について説明しています。フォーマンスが異常に低下している場合は、誤って再トレースしていないかどうかを確認することをお勧めします。\n",
        "\n",
        "eager-only の副次的効果（Python 引数の出力など）を追加して、関数がいつトレースされているかを確認できます。ここでは、新しい Python 引数が常に再トレースをトリガするため、余分な再トレースが発生していることを確認できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jsGQ4GQAP2Ve"
      },
      "outputs": [],
      "source": [
        "# Use @tf.function decorator\n",
        "@tf.function\n",
        "def a_function_with_python_side_effect(x):\n",
        "  print(\"Tracing!\")  # This eager\n",
        "  return x * x + tf.constant(2)\n",
        "\n",
        "# This is traced the first time\n",
        "print(a_function_with_python_side_effect(tf.constant(2)))\n",
        "# The second time through, you won't see the side effect\n",
        "print(a_function_with_python_side_effect(tf.constant(3)))\n",
        "\n",
        "# This retraces each time the Python argument chances\n",
        "# as a Python argument could be an epoch count or other\n",
        "# hyperparameter\n",
        "print(a_function_with_python_side_effect(2))\n",
        "print(a_function_with_python_side_effect(3))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D1kbr5ocpS6R"
      },
      "source": [
        "# 次のステップ\n",
        "\n",
        "より詳しい説明については、`tf.function` API リファレンスページと[ガイド](./function.ipynb)を参照してください。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "intro_to_graphs.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
